package com.lagou.edu;

import com.lagou.edu.mapper.*;
import com.lagou.edu.request.RequestProcessor;
import com.lagou.edu.servlet.HttpServlet;
import com.lagou.edu.utils.ExecutorProcessor;
import com.lagou.edu.utils.WebClassLoader;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author 赵虎
 * @date 2020/11/8 5:26 下午
 */
public class BootStrap {

    private static MapperServer mapperServer = new MapperServer();

    public void start() throws Exception {
        loadServer();

        int corePoolSize = 10;
        int maximumPoolSize = 50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );

        mapperServer.getMapperServiceList().forEach(mapperService -> {
            ExecutorProcessor executorProcessor = new ExecutorProcessor(mapperService);
            threadPoolExecutor.execute(executorProcessor);
        });
    }

    private  List<MapperWrapper> loadServlet(String webPath) throws DocumentException, ClassNotFoundException, IllegalAccessException, InstantiationException, FileNotFoundException {
        List<MapperWrapper> mapperWrapperList = new ArrayList<>();

        File file = new File(webPath + "/WEB-INF/web.xml");

        InputStream resourceAsStream = new FileInputStream(file);
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();

        List<Element> list = rootElement.selectNodes("//servlet");

        for (Element element : list) {
            MapperWrapper mapperWrapper = new MapperWrapper();

            Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
            String servletName = servletNameElement.getStringValue();

            Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
            String servletClass = servletClassElement.getStringValue();

            ClassLoader classLoader = new WebClassLoader(webPath);
            HttpServlet httpServlet = (HttpServlet) classLoader.loadClass(servletClass).newInstance();

            Element servletMappingElement = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");

            Element urlPatternElement = (Element) servletMappingElement.selectSingleNode("url-pattern");
            String urlPattern = urlPatternElement.getStringValue();
            mapperWrapper.setUrlPattern(urlPattern);

            // 类加载器
            mapperWrapper.setHttpServlet(httpServlet);
            mapperWrapperList.add(mapperWrapper);
        }
        return mapperWrapperList;
    }

    /**
     * 加载server
     */
    private void loadServer() throws DocumentException {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();

        List<Element> serviceList = rootElement.selectNodes("//Service");

        List<MapperService> mapperServiceList = new ArrayList<>();
        for (Element serviceElement : serviceList) {
            MapperService mapperService = loadService(serviceElement);
            mapperServiceList.add(mapperService);
        }
        mapperServer.setMapperServiceList(mapperServiceList);
    }


    /**
     * 加载service
     */
    private MapperService loadService(Element element) {
        MapperService mapperService = new MapperService();
        // service名称
        String serviceName = element.attributeValue("name");

        // 设置监听端口
        Element connectorElement = (Element) element.selectSingleNode("Connector");
        String connectorPort = connectorElement.attributeValue("port");

        // 设置engine
        Element engineElement = (Element) element.selectSingleNode("Engine");
        MapperEngine mapperEngine = loadEngine(engineElement);

        mapperService.setName(serviceName);
        mapperService.setPort(Integer.parseInt(connectorPort));
        mapperService.setMapperEngine(mapperEngine);
        return mapperService;
    }


    /**
     * 加载engine
     */
    private MapperEngine loadEngine(Element element) {
        MapperEngine mapperEngine = new MapperEngine();
        List<Element> hostElementList = element.selectNodes("Host");

        List<MapperHost> mapperHostList = new ArrayList<>();
        for (Element hostElement : hostElementList) {
            // 设置host
            MapperHost mapperHost = new MapperHost();
            String hostName = hostElement.attributeValue("name");
            String hostAppBase = hostElement.attributeValue("appBase");
            mapperHost.setName(hostName);
            mapperHost.setAppBase(hostAppBase);
            List<MapperContext> mapperContextList = loadContext(mapperHost);
            mapperHost.setMapperContextList(mapperContextList);
            mapperHostList.add(mapperHost);
        }

        mapperEngine.setMapperHostList(mapperHostList);
        return mapperEngine;
    }

    private List<MapperContext> loadContext(MapperHost mapperHost) {
        List<MapperContext> mapperContextList = new ArrayList<>();
        File file = new File(mapperHost.getAppBase());
        if (file.exists()) {
            File[] webDir = file.listFiles();
            if (webDir != null) {
                for (File web : webDir) {
                    try {
                        if(web.isDirectory()){
                            MapperContext mapperContext = new MapperContext();
                            List<MapperWrapper> mapperWrapperList = loadServlet(web.getPath());
                            mapperContext.setName(web.getName());
                            mapperContext.setMappedWrapperList(mapperWrapperList);
                            mapperContextList.add(mapperContext);
                        }
                    } catch (DocumentException | ClassNotFoundException | IllegalAccessException | InstantiationException | FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            try {
                throw new FileNotFoundException();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        return mapperContextList;
    }

    public static void main(String[] args) throws Exception {
        BootStrap bootStrap = new BootStrap();
        bootStrap.start();
    }
}
